using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace WindowsGame1
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        KeyboardState oldState;

        Random rand;
        float roughness = 0.9f;

        Texture2D heigthmap;
        Texture2D Pixel;
        Texture2D map;

        //int tamanio = 513^2;
        const int MAP_SIZE = 512;
        byte[,] mapita = new byte[MAP_SIZE + 1, MAP_SIZE + 1];
        byte[,] t_map = new byte[MAP_SIZE + 1, MAP_SIZE + 1];

        Color[] colors;
        //Byte[] colors;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            graphics.PreferredBackBufferHeight = MAP_SIZE;
            graphics.PreferredBackBufferWidth = MAP_SIZE;
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            base.Initialize();

            rand = new Random();
            Pixel = new Texture2D(graphics.GraphicsDevice, 1, 1);
            heigthmap = new Texture2D(graphics.GraphicsDevice, MAP_SIZE + 1, MAP_SIZE + 1);
            map = new Texture2D(graphics.GraphicsDevice, MAP_SIZE + 1, MAP_SIZE + 1);
           
            //colors = new Byte[1];
            //colors = new Color[1];
            //colors[0] = Color.Blue;

            Color[] col = new Color[1];
            col[0] = Color.White;
            Pixel.SetData<Color>(col);

           /* Color[] colors =
            {
            new Color(100,100,101),
            new Color(50,30,20),
            new Color(100,20,20),
            new Color(120,45,80),
            new Color(40,100,200),
            new Color(150,70,99),
            
            };*/

            /*colors[0] = Color.Wheat;
            colors[1] = Color.White;
            colors[2] = Color.Yellow;
            colors[3] = Color.Tomato;
            highmap.SetData<Color>(colors);*/
            //colors[0] = 255;
            //heigthmap.SetData<Byte>(colors);

            //heigthmap.SetData<Color>(colors);
            

            mapita[0, 0] = 127;
            mapita[MAP_SIZE, 0] = 127;
            mapita[0, MAP_SIZE] = 127;
            mapita[MAP_SIZE, MAP_SIZE] = 127;
            
            mapGenerator(0, 0, MAP_SIZE);
            generateThreshholdMap();
            CreateTexture(mapita, ref map);
            CreateTexture(t_map, ref heigthmap);

        }

        void UpdateInput()
        {
            KeyboardState newState = Keyboard.GetState();

            if (newState.IsKeyDown(Keys.Enter) && !oldState.IsKeyDown(Keys.Enter))
            {
                mapGenerator(0, 0, MAP_SIZE);
                generateThreshholdMap();
                CreateTexture(mapita, ref map);
                CreateTexture(t_map, ref heigthmap);
            }
            oldState = newState;
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            // TODO: use this.Content to load your game content here
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            // TODO: Add your update logic here
            UpdateInput();
            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);
            spriteBatch.Begin(SpriteBlendMode.AlphaBlend);
            // TODO: Add your drawing code here
            
            /*for ( int i = 0; i < MAP_SIZE; i++)
            {
                for (int j = 0; j < MAP_SIZE; j++)
                {
                    spriteBatch.Begin();
                    spriteBatch.Draw(heigthmap, new Vector2(i, j), new Color(mapita[i, j], mapita[i, j], mapita[i, j], 255));
                    spriteBatch.End();
                }
            }*/
            spriteBatch.Draw(map, Vector2.Zero, Color.Wheat);
            spriteBatch.Draw(heigthmap, Vector2.Zero, Color.Wheat);
            spriteBatch.End();
            base.Draw(gameTime);
        }

        public void mapGenerator(int x1, int y1, int w)
        {
            int maxDelta = (int) (w*127.0f / MAP_SIZE);
            byte delta = (byte)(rand.Next((int)(-w * roughness), (int) (w*roughness)));
            int tempValue = (int)delta + ((int)mapita[x1, y1] + (int)mapita[x1 + w, y1] + (int)mapita[x1, y1 + w] + (int)mapita[x1 + w, y1 + w]) / 4;

            /*mapita[x1 + w / 2, y1 + w / 2] = (delta + (mapita[x1, y1] + mapita[x1 + w, y1] + mapita[x1, y1 + w]));
            mapita[x1 + w / 2, y1 ] = ((mapita[x1, y1] + mapita[x1 + w, y1])/2);
            mapita[x1 + w / 2, y1 + w] = ((mapita[x1, y1 + w] + mapita[x1 + w, y1 + w]) / 2);
            mapita[x1, y1 + w / 2] = ((mapita[x1, y1] + mapita[x1, y1 + w]) / 2);
            mapita[x1 + w, y1 + w / 2] = ((mapita[x1 + w, y1] + mapita[x1 + w, y1 + w]) / 2);
            */

            mapita[x1 + w / 2, y1 + w / 2] = (byte)tempValue;
            //map[x1 + w / 2, y1 + w / 2] = (byte)(delta + (map[x1, y1] + map[x1 + w, y1] + map[x1, y1 + w] + map[x1 + w, y1 + w]) / 4);
            mapita[x1 + w / 2, y1] = (byte)((mapita[x1, y1] + mapita[x1 + w, y1]) / 2);
            mapita[x1 + w / 2, y1 + w] = (byte)((mapita[x1, y1 + w] + mapita[x1 + w, y1 + w]) / 2);
            mapita[x1, y1 + w / 2] = (byte)((mapita[x1, y1] + mapita[x1, y1 + w]) / 2);
            mapita[x1 + w, y1 + w / 2] = (byte)((mapita[x1 + w, y1] + mapita[x1 + w, y1 + w]) / 2);

            if (w >= 2)
            {
                mapGenerator(x1, y1, w / 2);
                mapGenerator(x1 + w / 2, y1, w / 2);
                mapGenerator(x1, y1 + w / 2, w / 2);
                mapGenerator(x1 + w / 2, y1 + w / 2, w / 2);
            }
        }

        public void CreateTexture(byte[,] source,ref Texture2D destination)
        { 
            Color[] colorArray = new Color[destination.Width*destination.Width];
            int pos = 0;
            for (int i = 0; i < destination.Width; i++)
            {
                for(int j = 0; i > destination.Width; j++)
                {
                    colorArray[pos] = new Color(source[i, j], source[i, j], source[i, j]);
                    pos++;
                }
                destination.GetData<Color>(colorArray);
            }
        }

        void generateThreshholdMap()
        {
            for (int i = 0; i < MAP_SIZE + 1; i++)
            {
                for (int j = 0; j < MAP_SIZE + 1; j++)
                {
                    t_map[i, j] = (byte)(mapita[i, j] > 127 ? 255 : 0);
                }
            }
        }
    }
}
